package org.arquimedes.dispatcher;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import org.arquiemedes.utilitarios.Constantes;
import org.arquimedes.dispatcher.hilos.GrupoHilos;
import org.arquimedes.dispatcher.hilos.HiloProcesadorAlarmas;
import org.arquimedes.servicios.ServicioEnviarMail;
import org.arquimedes.servicios.ServicioLNegra;

/**
 * Encargada de la replicacion de las tramas a los sistemas de procesamiento de alarmas
 * @author Juan David Ramirez
 * @since 4/07/2011
 *
 */
public class Replicador {

	/**
	 * Listado de las ips de los procesadores
	 */
	private ArrayList<InfoProcesadorAlarmas> listaIpProcesadoresAlarmas;
	
	/**
	 * N�mero de trama recibida, esto es para no reenviar la informaci�n
	 */
	private int numeroTrama=0;
	
	/**
	 * Instancia del replicador
	 */
	private static Replicador replicador=null;
	
	/**
	 * Constructor
	 * @param listaIpProcesadoresAlarmas
	 */
	private Replicador(ArrayList<InfoProcesadorAlarmas> listaIpProcesadoresAlarmas) {
		this.listaIpProcesadoresAlarmas=listaIpProcesadoresAlarmas;
	}
	
	/**
	 * Obtiene la instancia del replicador
	 * @return Instancia
	 */
	public static Replicador obtenerReplicador()
	{
		if(replicador==null)
		{
			throw new RuntimeException("Replicador no inicializado");
		}
		return replicador;
	}
	
	/**
	 * Grupo de hilos por petici�n
	 */
	private HashMap<Integer, GrupoHilos> grupoHilosPeticion;
	
	/**
	 * Iniciar el replicador
	 * @param encKey {@link String} llave privada para la desencripci�n
	 * @param sigToVerify {@link String} con la trama a replicar encriptada
	 * @param ip {@link String} con la ip del host procesado
	 */
	public void replicarTrama(byte[] encKey, byte[] sigToVerify, String ip) throws IOException {
		GrupoHilos hilos=new GrupoHilos(numeroTrama, ip);
		
		for(InfoProcesadorAlarmas procesaror:listaIpProcesadoresAlarmas)
		{
			if(procesaror.isActivo())
			{
				HiloProcesadorAlarmas hilo=new HiloProcesadorAlarmas(numeroTrama, encKey, sigToVerify, procesaror.getIp());
				hilo.run();
				hilos.adicionarHiloProcesamiento(numeroTrama, hilo);
			}
		}
		grupoHilosPeticion.put(numeroTrama, hilos);
	}

	/**
	 * Aceptar la respuesta de un hilo que termin� el procesamiento
	 * @param identificador Identificador del proceso
	 * @param mensaje mensaje para ser enviado a las autoridades
	 * @param mailTo correo donde se va a enviar el mensaje! 
	 */
	public synchronized void responderProceso(int identificador, int respuesta, String mensaje, String mailTo)
	{
		GrupoHilos grupo=grupoHilosPeticion.get(identificador);
		String ip=grupo.getIpFuente();

		grupo.finalizarTodosHilos();
		
		// Liberar la memoria
		grupoHilosPeticion.remove(identificador);
		grupo=null;
		
		switch(respuesta)
		{
			case Constantes.BLOQUEAR_IP:
				ServicioLNegra.getServicio().agregarListaNegra(ip);
				break;
			case Constantes.LLAMAR_AUTORIDADES:
				ServicioEnviarMail.getServicio().enviarMensajeAMail(mailTo, mensaje);
				break;
			 default:
				System.out.println("Respuesta inv�lida");
		}
	}

	/**
	 * Informaci�n de baja del sistema
	 * @param ip Ip del sistema de procesamiento con problemas
	 */
	public void informarBajaSistema(String ip) {
		for(InfoProcesadorAlarmas procesador:listaIpProcesadoresAlarmas)
		{
			if(ip.equals(procesador.getIp()) && procesador.isActivo())
			{
				procesador.setActivo(false);
				// TODO Crear correo para el administrador
				System.out.println("Se env�a correo administrador, cae sistema ip:"+ip);
				break;
			}
		}
	}
	
	/**
	 * Agrega un nuevo procesador de alarmas al sistema
	 * @param ip Ip del procesador a agregar
	 */
	public void adicionarProcesadorAlarmas(String ip)
	{
		for(InfoProcesadorAlarmas procesador:listaIpProcesadoresAlarmas)
		{
			if(procesador.getIp().equals(ip))
			{
				procesador.setActivo(true);
				// Si la ip exist�a, entonces activa el procesador que posiblemente estaba inactivo
				return;
			}
		}
		InfoProcesadorAlarmas procesador=new InfoProcesadorAlarmas(ip);
		listaIpProcesadoresAlarmas.add(procesador);
	}
	
	/**
	 * Iniciar el replicador de alarmas
	 * @param listaIpProcesadoresAlarmas Lista de ips de los procesadores de alarmas
	 */
	public static void iniciarReplicador(ArrayList<String> listaIps){
		ArrayList<InfoProcesadorAlarmas> listaProcesadoresAlarmas=new ArrayList<InfoProcesadorAlarmas>();
		for(String ip:listaIps)
		{
			InfoProcesadorAlarmas procesador=new InfoProcesadorAlarmas(ip);
			listaProcesadoresAlarmas.add(procesador);
		}
		replicador=new Replicador(listaProcesadoresAlarmas);
	}
}
